<?php

namespace app\admin\service;

use app\admin\dao\UserPersonnelDao;
use app\admin\model\UM as UM;
use app\admin\traits\AdminCheckTrait;
use app\common\model\Member;
use app\common\model\Role;
use app\common\model\User;
use app\common\model\UserPersonnel;
use app\common\service\TemplateSmsService;
use ShidianUtil\Exception\DataNotExistException;
use ShidianUtil\Utils\StringUtil;
use think\exception\ValidateException;

/**
 * Class PersonnelService
 * @package app\admin\service
 */
class PersonnelService
{
    use AdminCheckTrait;

    // dao
    private UserPersonnelDao $userPersonnelDao;

    public function __construct(UserPersonnelDao $userPersonnelDao)
    {
        $this->userPersonnelDao = $userPersonnelDao;
    }

    /**
     * 列表
     * @param UM $user
     * @param int|null $page
     * @param int|null $page_size
     * @return array
     */
    public function index(UM $user, $companyId, ?int $page = null, ?int $page_size = null): array
    {
        if (StringUtil::equals($user->roleType, Role::ROLE_TYPE_COMPANY)) {
            $companyId = $user->id;
        }

        //这里如果要修改查询，建议把查询放到dao层去
        return $this->userPersonnelDao->listPersonnels($companyId, $page, $page_size);
    }

    /**
     * 查询
     * @param UM|null $user
     * @param int $id
     * @return UserPersonnel
     */
    public function read(?UM $user, int $id): ?UserPersonnel
    {
        //这里如果要修改查询，建议把查询放到dao层去
        return $this->userPersonnelDao->findByPK($id, true);
    }

    /**
     * 新增
     * @param UM $user
     * @param array $params
     * @return UserPersonnel
     */
    public function add(UM $user, array $params): UserPersonnel
    {
        if (StringUtil::equals($user->roleType, Role::ROLE_TYPE_COMPANY)) {
            $params['companyId'] = $user->id;
        } else {
            if (!is_id($params['companyId'] ?? null)) {
                throw new ValidateException('请选择一家公司');
            }
        }

        $company = User::where('id', $params['companyId'])->find();
        if (!$company) {
            throw new ValidateException('该公司不存在或已被删除');
        }
        $companyName = $company->name;

        // mobile
        $mobile = $params['mobile'] ?? null;

        // 手机号是否被占用
        $this->checkMobile($mobile);

        // 检查是否能邀请该手机号
        $this->checkMember($mobile);

        $this->checkQuota($params);

        $record = $this->userPersonnelDao->insertActive($params, []);

        // 邀请绑定
        $this->inviteBind($mobile, $companyName, $record->id);

        return $record;
    }

    /**
     * 更新
     * @param UM $user
     * @param int $id
     * @param array $params
     * @return UserPersonnel
     */
    public function modify(UM $user, int $id, array $params): UserPersonnel
    {
        //这里如果要修改查询，建议把查询就放到这里
        $record = UserPersonnel::where('id', $id)
            ->field(true)
            ->with(['member'])
            ->find();

        if (is_null($record)) {
            throw new DataNotExistException('该员工不存在或已被删除');
        }

        $this->checkAdminOrSelfCompany($user, $record->companyId, '您只能修改本公司员工');

        $company = User::where('id', $record->companyId)->find();
        if (!$company) {
            throw new ValidateException('该公司不存在或已被删除');
        }
        $companyName = $company->name;


        $oldMobile = $record->mobile;
        $mobile = $params['mobile'] ?? null;

        $this->checkMobile($mobile, $id);

        // 修改了手机号
        if (not_blank($mobile) && !StringUtil::equals($oldMobile, $mobile)) {

            if ($record->member) {
                // 已绑定

                // 修改用户账号手机号
                $this->getMemberPhoneService()->updateMemberPhone($record->member->id, $mobile);

            } else {
                // 未绑定

                // 检查是否能邀请该手机号
                $this->checkMember($mobile);
            }
        }

        $this->checkQuota($params);

        // 修改员工信息
        $allowField = ['name', 'mobile', 'desc', 'quotaCard', 'quotaCoin'];
        $this->userPersonnelDao->updateActive($record, $params, $allowField);

        if (not_blank($mobile) && !StringUtil::equals($oldMobile, $mobile)) {
            if (!$record->member) {
                // 邀请绑定
                $this->inviteBind($mobile, $companyName, $record->id);
            }
        }

        return $record;
    }

    /**
     * 删除
     * @param UM $user
     * @param int $id
     */
    public function rm(UM $user, int $id): void
    {

        //这里如果要修改查询，建议把查询就放到这里
        $record = UserPersonnel::where('id', $id)
            ->field(true)
            ->with(['member'])
            ->find();

        if (is_null($record)) {
            return;
        }

        $this->checkAdminOrSelfCompany($user, $record->companyId, '您只能移除本公司员工');

        if ($record->member) {
            throw new ValidateException('该员工已绑定账号，不能删除');
        }

        $this->userPersonnelDao->deleteModel($record);
    }

    /**
     * 尝试绑定用户到员工
     * @param Member $member
     * @return void
     */
    public function bindPersonnel(Member $member): void
    {
        $phone = $member->phone;

        $userPersonnel = UserPersonnel::where('mobile', $phone)->find();
        if (!$userPersonnel) {
            return;
        }

        $this->bindMemberAndPersonnel($member, $userPersonnel);
    }

    /**
     * 绑定指定用户到指定员工
     * @param Member $member
     * @param UserPersonnel $userPersonnel
     * @return void
     */
    public function bindMemberAndPersonnel(Member $member, UserPersonnel $userPersonnel): void
    {

        if (!StringUtil::equals($member->phone, $userPersonnel->mobile)) {
            throw new ValidateException('手机号不一致');
        }

        if (is_id($member->userPersonnelId)) {
            throw new ValidateException('该用户已经绑定');
        }

        $m = Member::where('userPersonnelId', $userPersonnel->id)->find();
        if ($m) {
            throw new ValidateException('该员工已经绑定');
        }

        // 绑定邀请
        $member->companyId = $userPersonnel->companyId;
        $member->userPersonnelId = $userPersonnel->id;
        $member->save();

        // 写入定制推送
        $cityId = 0;
        if (isset($member->cityId) && is_id($member->cityId)) {
            $cityId = $member->cityId;
        }
        $this->getLawyerDraftCheckService()->saveCustomPush($member->id, $cityId);
    }

    /**
     * 手机号不能重复
     * @param $mobile
     * @param $id
     * @return void
     */
    private function checkMobile($mobile, $id = null)
    {
        $repeat = UserPersonnel::where('mobile', $mobile)
            ->when(is_id($id), fn($query) => $query->where('id', '<>', $id))
            ->find();

        if ($repeat) {
            throw new ValidateException('该手机号已被其他员工绑定');
        }
    }

    /**
     * 检查手机号对应用户是否可以被添加（未注册也可以）
     * @param $mobile
     * @return void
     */
    private function checkMember($mobile): void
    {
        $record = Member::where('phone', $mobile)->whereIn('status', [0, 1])->find();

        if ($record) {

            if (!StringUtil::equals($record->status, '1')) {
                throw new ValidateException('该用户已被封禁，请输入其他手机号');
            }

            if (is_id($record->userPersonnelId)) {
                throw new ValidateException('该用户已绑定，请输入其他手机号');
            }
        }

        // 允许绑定未注册的（注册时自动绑定）
    }

    /**
     * 发邀请绑定短信
     * @param $mobile
     * @param $companyName
     * @param $userPersonnelId
     * @return void
     */
    public function inviteBind($mobile, $companyName, $userPersonnelId)
    {
        $record = Member::where('phone', $mobile)->whereIn('status', [0, 1])->find();

        if ($record && !is_id($record->userPersonnelId)) {

            $this->getTemplateSmsService()->invitePersonnel($mobile, $companyName, $userPersonnelId);
        }
    }

    private function checkQuota(&$params): void
    {
        $params['quotaCard'] = (int)$params['quotaCard'];
        $params['quotaCoin'] = (int)$params['quotaCoin'];
    }

    private function getMemberPhoneService(): MemberPhoneService
    {
        return app(MemberPhoneService::class);
    }

    private function getTemplateSmsService(): TemplateSmsService
    {
        return app(TemplateSmsService::class);
    }

    private function getLawyerDraftCheckService(): LawyerDraftCheckService
    {
        return app(LawyerDraftCheckService::class);
    }
}
